//
//  LcCellAdapter.m
//  18Birdies
//
//  Created by Lc on 15/4/2.
//  Copyright (c) 2015年 Lc. All rights reserved.
//

#import <mach/mach_time.h>
//#import "DefaultTextCellData.h"
#import "LcCell.h"
#import "LcCellAdapter.h"
#import "LcCellData.h"
#import "LcLoadMoreView.h"
#import "LcLog.h"
#import "LcPreconditions.h"
#import "LcSelectableCellData.h"
#import "LcSwitchableCellData.h"
#import "NSDate+Lc.h"

@interface LcCellAdapter ()<LcLoadMoreViewDelegate>
@property(nonatomic, strong) NSMutableArray* cellDatas;
@property(nonatomic, strong) NSMutableSet* ids;
@property(nonatomic, strong) LcLoadMoreView* loadMoreView;

//@property(nonatomic, strong) DefaultTextCellData* defaultTextCellData;
@end

@implementation LcCellAdapter

- (instancetype)init {
  self = [super init];
  if (self) {
    self.cellDatas = [NSMutableArray array];
    self.ids = [NSMutableSet set];
//    self.defaultTextCellData = [DefaultTextCellData cellData];
  }
  return self;
}

- (void)addCellDatas:(NSArray*)cellDatas {
  for (LcCellData* cellData in cellDatas) {
    LC_CHECK_TRUE([cellData isKindOfClass:LcCellData.class]);
    [self addCellData:cellData];
  }
}

- (void)addCellData:(LcCellData*)cellData {
  LC_CHECK_NOT_NULL(cellData);
  cellData.cellAdapter = self;
  [self.cellDatas addObject:cellData];
}

- (void)insertCellDatas:(NSArray*)cellDatas atIndex:(int)index {
  LC_CHECK_NOT_EMPTY(cellDatas);
  for (int i = (int)(cellDatas.count - 1); i >= 0; --i) {
    LcCellData* cellData = cellDatas[i];
    cellData.cellAdapter = self;
    [self.cellDatas insertObject:cellData atIndex:index];
  }
}

- (void)removeCellData:(LcCellData*)cellData count:(int)count {
  LC_CHECK_NOT_NULL(cellData);
  LC_CHECK_TRUE(count > 0);
  NSUInteger index = [self.cellDatas indexOfObject:cellData];
  if (index != NSNotFound) {
    for (int i = 0; i < count; ++i) {
      [self.cellDatas removeObjectAtIndex:index];
    }
  }
}

- (void)removeAllCellDatas {
  [self.cellDatas removeAllObjects];
  [self.ids removeAllObjects];
}

- (NSArray*)allCellDatas {
  return self.cellDatas;
}

- (NSArray*)cellDatasOfClass:(Class)aClass {
  NSMutableArray* cellDatas = [NSMutableArray array];
  for (LcCellData* cellData in self.cellDatas) {
    if ([cellData isKindOfClass:aClass]) {
      [cellDatas addObject:cellData];
    }
  }
  return cellDatas;
}

- (LcCellData*)cellDataInGroup:(NSString*)group {
  for (LcCellData* cellData in self.cellDatas) {
    if ([cellData.group isEqualToString:group]) {
      return cellData;
    }
  }
  return nil;
}

- (NSArray*)cellDatasInGroup:(NSString*)group {
  NSMutableArray* cellDatas = [NSMutableArray array];
  for (LcCellData* cellData in self.cellDatas) {
    if ([cellData.group isEqualToString:group]) {
      [cellDatas addObject:cellData];
    }
  }
  return cellDatas;
}

- (LcCell*)cellWithCellData:(LcCellData*)cellData {
  LC_CHECK_NOT_NULL(cellData);
  NSUInteger index = [self.allCellDatas indexOfObject:cellData];
  if (index != NSNotFound) {
    return [self cellAtIndex:(int)index];
  }
  return nil;
}

- (LcCell*)cellAtIndex:(int)index {
  LC_CHECK_TRUE(index >= 0 && index < self.allCellDatas.count);
  NSIndexPath* indexPath = [NSIndexPath indexPathForRow:index inSection:0];
  LcCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
  return cell;
}

- (void)insertCellDatas:(NSArray*)cellDatas
                atIndex:(int)index
           useAnimation:(UITableViewRowAnimation)rowAnimation {
  [self insertCellDatas:cellDatas atIndex:index];
  NSMutableArray* indexPaths =
      [NSMutableArray arrayWithCapacity:cellDatas.count];
  for (int i = 0; i < cellDatas.count; i++) {
    [indexPaths addObject:[NSIndexPath indexPathForRow:i + index inSection:0]];
  }
  [self.tableView insertRowsAtIndexPaths:indexPaths
                        withRowAnimation:rowAnimation];
}

- (void)replaceCellData:(LcCellData*)cellData
           withCellData:(LcCellData*)newCellData
           useAnimation:(UITableViewRowAnimation)rowAnimation {
  NSUInteger index = [self indexOfCellData:cellData];
  LC_CHECK_TRUE(index != NSNotFound);
  [self removeCellData:cellData count:1];

  [self.tableView beginUpdates];
  [self.tableView deleteRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index
                                                               inSection:0] ]
                        withRowAnimation:UITableViewRowAnimationAutomatic];
  [self insertCellDatas:@[ newCellData ] atIndex:(int)index];
  [self.tableView insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index
                                                               inSection:0] ]
                        withRowAnimation:rowAnimation];
  [self.tableView endUpdates];
}

- (void)removeCellData:(LcCellData*)cellData
                 count:(int)count
         userAnimation:(UITableViewRowAnimation)rowAnimation {
  int index = (int)[self indexOfCellData:cellData];
  [self removeCellData:cellData count:count];
  NSMutableArray* indexPaths = [NSMutableArray arrayWithCapacity:count];
  for (int i = 0; i < count; i++) {
    [indexPaths addObject:[NSIndexPath indexPathForRow:i + index inSection:0]];
  }
  [self.tableView deleteRowsAtIndexPaths:indexPaths
                        withRowAnimation:rowAnimation];
}

- (id)cellDataAtIndex:(int)index {
  return self.cellDatas[index];
}

- (NSUInteger)indexOfCellData:(LcCellData*)cellData {
  return [self.cellDatas indexOfObject:cellData];
}

- (NSArray*)removeDuplicates:(NSArray*)withIdObjects {
  return withIdObjects;
}

- (void)setHasMore:(BOOL)hasMore {
  self->_hasMore = hasMore;
  if (hasMore) {
    if (self.loadMoreView == nil) {
      self.loadMoreView = [LcLoadMoreView loadMoreView];
      self.loadMoreView.delegate = self;
    }
    self.tableView.tableFooterView = self.loadMoreView;
  } else {
    self.tableView.tableFooterView = nil;
  }
}

- (void)loadMoreFinished {
  if (self.loadMoreView != nil) {
    self.loadMoreView.isLoading = NO;
  }
}

- (void)onLoadMore:(LcLoadMoreView*)loadMoreView {
  loadMoreView.isLoading = YES;
  LC_CHECK_NOT_NULL(self.delegate);
  [self.delegate onLoadMore:self];
}

- (NSInteger)tableView:(UITableView*)tableView
    numberOfRowsInSection:(NSInteger)section {
  return self.cellDatas.count;
}

- (UITableViewCell*)tableView:(UITableView*)tableView
        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
  LcCellData* cellData = self.cellDatas[indexPath.row];
  LcCell* cell = [tableView dequeueReusableCellWithIdentifier:cellData.reuseId];
  if (cell == nil) {
#ifdef DEBUG
    //    long long timestamp = [NSDate currentTimeMillis];
    uint64_t begin = mach_absolute_time();
#endif
    cell = cellData.newCell;
#ifdef DEBUG
    //    LcLog(@"New cell of %@, use %lldms", cellData.reuseId,
    //          [NSDate currentTimeMillis] - timestamp);
    uint64_t end = mach_absolute_time();
    mach_timebase_info_data_t timebase;
    mach_timebase_info(&timebase);
    double elapsedMillisecond = ((double)(end - begin)) *
                                (double)timebase.numer /
                                (double)timebase.denom / 1e6;
    LcLog(@"New cell of %@, use %.3lfms", cellData.reuseId, elapsedMillisecond);
#endif
  } else {
    [cellData refreshCell:cell];
    [cellData postRefreshCell:cell];
  }
  return cell;
}

- (CGFloat)tableView:(UITableView*)tableView
    heightForRowAtIndexPath:(NSIndexPath*)indexPath {
  return [self.cellDatas[indexPath.row] cellHeight];
}

- (void)tableView:(UITableView*)tableView
      willDisplayCell:(UITableViewCell*)cell
    forRowAtIndexPath:(NSIndexPath*)indexPath {
  if (indexPath.row < self.cellDatas.count) {
    [self.cellDatas[indexPath.row] willDisplayCell:(LcCell*)cell];
  }
}

- (void)tableView:(UITableView*)tableView
    didEndDisplayingCell:(UITableViewCell*)cell
       forRowAtIndexPath:(NSIndexPath*)indexPath {
  if (indexPath.row < self.cellDatas.count) {
    [self.cellDatas[indexPath.row] didDismissCell:(LcCell*)cell];
  }
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
  return [self.cellDatas[indexPath.row] canEdit];
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
  LC_CHECK_NOT_NULL(self.delegate);
  [self.delegate onCommitEditing:indexPath cellAdapter:self];
}

- (void)onRowSelectedAtIndex:(NSInteger)index {
  LC_CHECK_TRUE(index < self.cellDatas.count);
  if ([self.cellDatas[index] clickable]) {
    if ([self.cellDatas[index] onCellClickedHandler] != nil) {
      [self.cellDatas[index] onCellClickedHandler](self.cellDatas[index]);
    } else if (self.onCellAdapterClickedHanlder != nil) {
      self.onCellAdapterClickedHanlder(self.cellDatas[index]);
    }
  }
}

- (void)refreshCell:(LcCellData*)cellData {
  LC_CHECK_NOT_NULL(cellData);
  LC_CHECK_IS_MAIN_THREAD();
  NSUInteger index = [self.cellDatas indexOfObject:cellData];
  if (index != NSNotFound) {
    [self.tableView reloadRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index
                                                                 inSection:0] ]
                          withRowAnimation:UITableViewRowAnimationNone];
  }
}

- (void)refreshCellArray:(NSArray*)cellDatas {
  LC_CHECK_IS_MAIN_THREAD();
  NSMutableArray* indexPathes = [NSMutableArray array];
  for (LcCellData* cellData in cellDatas) {
    NSUInteger row = [self.cellDatas indexOfObject:cellData];
    [indexPathes addObject:[NSIndexPath indexPathForRow:row inSection:0]];
  }
  if (indexPathes.count > 0) {
    [self.tableView reloadRowsAtIndexPaths:indexPathes withRowAnimation:UITableViewRowAnimationNone];
  }
}

- (void)refreshCells:(NSString*)group {
  LC_CHECK_NOT_EMPTY(group);
  LC_CHECK_IS_MAIN_THREAD();
  NSMutableArray* indexPathes = [NSMutableArray array];
  int count = (int)self.cellDatas.count;
  for (int i = 0; i < count; ++i) {
    LcCellData* cellData = self.cellDatas[i];
    if ([cellData.group isEqualToString:group]) {
      [indexPathes addObject:[NSIndexPath indexPathForRow:i inSection:0]];
    }
  }
  if (indexPathes.count > 0) {
    [self.tableView reloadRowsAtIndexPaths:indexPathes
                          withRowAnimation:UITableViewRowAnimationNone];
  }
}

- (void)refreshAllCells {
  [self.tableView reloadData];
}

- (void)selectCellData:(LcSelectableCellData*)selectableCellData
    deselectOthersInGroup:(BOOL)deselectOthersInGroup {
  if (!selectableCellData.selected) {
    selectableCellData.selected = YES;
    if (deselectOthersInGroup) {
      LC_CHECK_NOT_EMPTY(selectableCellData.group);
      for (LcCellData* cellData in self.cellDatas) {
        if (cellData == selectableCellData) {
          continue;
        }
        if ([cellData.group isEqualToString:selectableCellData.group]) {
          if ([cellData isKindOfClass:LcSelectableCellData.class]) {
            ((LcSelectableCellData*)cellData).selected = NO;
          }
        }
      }
      [self refreshCells:selectableCellData.group];
    } else {
      [self refreshCell:selectableCellData];
    }
    if (self.delegate != nil) {
      [self.delegate onSelectionChanged:selectableCellData.group
                            cellAdapter:self];
    }
  }
}

- (LcSelectableCellData*)selectedCellDataInGroup:(NSString*)group {
  for (LcCellData* cellData in self.cellDatas) {
    if ([cellData.group isEqualToString:group]) {
      if ([cellData isKindOfClass:LcSelectableCellData.class]) {
        if (((LcSelectableCellData*)cellData).selected) {
          return (LcSelectableCellData*)cellData;
        }
      }
    }
  }
  return nil;
}

- (NSArray*)selectedCellDatasInGroup:(NSString*)group {
  NSMutableArray* selectedCellDatas = [NSMutableArray array];
  for (LcCellData* cellData in self.cellDatas) {
    if ([cellData.group isEqualToString:group]) {
      if ([cellData isKindOfClass:LcSelectableCellData.class]) {
        if (((LcSelectableCellData*)cellData).selected) {
          [selectedCellDatas addObject:cellData];
        }
      }
    }
  }
  return selectedCellDatas;
}

- (void)hide:(LcCellData*)cellData
            hidden:(BOOL)hidden
    needAutoScroll:(BOOL)needAutoScroll {
  LC_CHECK_NOT_NULL(cellData);
  LC_CHECK_IS_MAIN_THREAD();
  if (cellData.hidden == hidden) {
    return;
  }
  const NSUInteger index = [self.cellDatas indexOfObject:cellData];
  if (index != NSNotFound) {
    cellData.hidden = hidden;
    [self.tableView
        reloadRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index
                                                     inSection:0] ]
              withRowAnimation:hidden ? UITableViewRowAnimationTop
                                      : UITableViewRowAnimationBottom];
    if (!hidden && needAutoScroll) {
      LcCell* cell = (LcCell*)[self.tableView
          cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index
                                                   inSection:0]];
      if (cell == nil) {
        [self.tableView
            scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index
                                                      inSection:0]
                  atScrollPosition:UITableViewScrollPositionBottom
                          animated:YES];
      } else {
        if (cell.frame.origin.y - self.tableView.contentOffset.y +
                cell.cellData.cellHeight >
            self.tableView.bounds.size.height) {
          [self.tableView
              scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index
                                                        inSection:0]
                    atScrollPosition:UITableViewScrollPositionBottom
                            animated:YES];
        }
      }
    }
  }
}

- (void)hideToLastMember:(LcCellData*)cellData hidden:(BOOL)hidden {
  [self hideToLastMember:cellData hidden:hidden animated:YES];
}

- (void)hideToLastMember:(LcCellData*)cellData
                  hidden:(BOOL)hidden
                animated:(BOOL)animated {
  LC_CHECK_NOT_NULL(cellData);
  LC_CHECK_IS_MAIN_THREAD();
  if (cellData.lastMemberCellData == nil) {
    LC_DEBUG_FAIL();
    return;
  }
  const NSUInteger index = [self.cellDatas indexOfObject:cellData];
  const NSUInteger lastMemberIndex =
      [self.cellDatas indexOfObject:cellData.lastMemberCellData];
  if (index != NSNotFound && lastMemberIndex != NSNotFound &&
      index < lastMemberIndex) {
    NSMutableArray* indexPaths = [NSMutableArray array];
    for (int i = (int)index + 1; i <= lastMemberIndex; ++i) {
      LcCellData* cellData = self.cellDatas[i];
      cellData.hidden = hidden;
      [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
      if (!hidden) {
        LcCellData* subLastMember = cellData.lastMemberCellData;
        if (subLastMember != nil) {
          NSUInteger subLastMemberIndex =
              [self.cellDatas indexOfObject:subLastMember];
          if (subLastMemberIndex != NSNotFound) {
            i = (int)subLastMemberIndex;
          }
          if ([cellData isKindOfClass:LcSwitchableCellData.class]) {
            if (((LcSwitchableCellData*)cellData).switchOn) {
              [self hideToLastMember:cellData hidden:NO];
            }
          }
        }
      }
    }
    if (animated) {
      if (@available(iOS 11.0, *)) {
        // fix bug: 20585
        [self.tableView reloadRowsAtIndexPaths:indexPaths
                              withRowAnimation:UITableViewRowAnimationAutomatic];
      } else {
        [self.tableView reloadRowsAtIndexPaths:indexPaths
                              withRowAnimation:hidden ? UITableViewRowAnimationTop
                                                      : UITableViewRowAnimationBottom];
      }

      if (!hidden) {
        LcCell* cell = (LcCell*)[self.tableView
            cellForRowAtIndexPath:[NSIndexPath indexPathForRow:lastMemberIndex
                                                     inSection:0]];
        if (cell == nil) {
          [self.tableView
              scrollToRowAtIndexPath:[NSIndexPath
                                         indexPathForRow:lastMemberIndex
                                               inSection:0]
                    atScrollPosition:UITableViewScrollPositionBottom
                            animated:YES];
        } else {
          if (cell.frame.origin.y - self.tableView.contentOffset.y +
                  cell.cellData.cellHeight >
              self.tableView.bounds.size.height) {
            [self.tableView
                scrollToRowAtIndexPath:[NSIndexPath
                                           indexPathForRow:lastMemberIndex
                                                 inSection:0]
                      atScrollPosition:UITableViewScrollPositionBottom
                              animated:YES];
          }
        }
      }
    }
  }
}

- (void)hideFromMember:(LcCellData*)fromCellData
              toMember:(LcCellData*)toCellData
                hidden:(BOOL)hidden
              animated:(BOOL)animated {
  LC_CHECK_NOT_NULL(fromCellData);
  LC_CHECK_NOT_NULL(toCellData);
  LC_CHECK_IS_MAIN_THREAD();
  
  const NSUInteger fromIndex = [self.cellDatas indexOfObject:fromCellData];
  const NSUInteger toIndex = [self.cellDatas indexOfObject:toCellData];
  if (fromIndex != NSNotFound && toIndex != NSNotFound &&
      fromIndex < toIndex) {
    NSMutableArray* indexPaths = [NSMutableArray array];
    for (int i = (int)fromIndex + 1; i < toIndex; ++i) {
      LcCellData* cellData = self.cellDatas[i];
      cellData.hidden = hidden;
      [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
      if (!hidden) {
        LcCellData* subLastMember = cellData.lastMemberCellData;
        if (subLastMember != nil) {
          NSUInteger subLastMemberIndex =
          [self.cellDatas indexOfObject:subLastMember];
          if (subLastMemberIndex != NSNotFound) {
            i = (int)subLastMemberIndex;
          }
          if ([cellData isKindOfClass:LcSwitchableCellData.class]) {
            if (((LcSwitchableCellData*)cellData).switchOn) {
              [self hideToLastMember:cellData hidden:NO];
            }
          }
        }
      }
    }
    if (animated) {
      [self.tableView
       reloadRowsAtIndexPaths:indexPaths
       withRowAnimation:hidden ? UITableViewRowAnimationTop
       : UITableViewRowAnimationBottom];
      if (!hidden) {
        LcCell* cell = (LcCell*)[self.tableView
                                 cellForRowAtIndexPath:[NSIndexPath indexPathForRow:toIndex
                                                                          inSection:0]];
        if (cell == nil) {
          [self.tableView
           scrollToRowAtIndexPath:[NSIndexPath
                                   indexPathForRow:toIndex
                                   inSection:0]
           atScrollPosition:UITableViewScrollPositionBottom
           animated:YES];
        } else {
          if (cell.frame.origin.y - self.tableView.contentOffset.y +
              cell.cellData.cellHeight >
              self.tableView.bounds.size.height) {
            [self.tableView
             scrollToRowAtIndexPath:[NSIndexPath
                                     indexPathForRow:toIndex
                                     inSection:0]
             atScrollPosition:UITableViewScrollPositionBottom
             animated:YES];
          }
        }
      }
    }
  }
}

//- (void)setDefaultCellText:(NSString*)text {
//  LC_CHECK_NOT_EMPTY(text);
//  self.defaultTextCellData.text = text.copy;
//  self.defaultTextCellData.attributedText = nil;
//}
//
//- (void)setDefaultCellAttributeText:(NSAttributedString*)attributeText {
//  LC_CHECK_NOT_EMPTY(attributeText);
//  self.defaultTextCellData.text = nil;
//  self.defaultTextCellData.attributedText = attributeText.copy;
//}
//
//- (void)setDefaultCellTopMargin:(CGFloat)topMargin {
//  self.defaultTextCellData.textTopMargin = topMargin;
//}
//
//- (void)showDefaultCell {
//  if (![self.cellDatas containsObject:self.defaultTextCellData]) {
//    [self.cellDatas addObject:self.defaultTextCellData];
//    [self refreshAllCells];
//  }
//}
//
//- (void)hideDefaultCell {
//  if ([self.cellDatas containsObject:self.defaultTextCellData]) {
//    [self.cellDatas removeObject:self.defaultTextCellData];
//    [self refreshAllCells];
//  }
//}

@end
